using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

using System.Net;
using System.Net.Mail;
using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Collections.Specialized;

namespace Pitoshka.Tools.Helpers
{
	public class MailHelper
	{
		#region Static properties
		private static string _SMTP;
		public static string SMTP
		{
			get { return _SMTP; }
			set { _SMTP = value; }
		}

		private static int _Port = 25;
		public static int Port
		{
			get { return _Port; }
			set { _Port = value; }
		}


		private static string _SmtpUserName;
		public static string SmtpUserName
		{
			get { return _SmtpUserName; }
			set { _SmtpUserName = value; }
		}

		private static string _SmtpUserPassword;
		public static string SmtpUserPassword
		{
			get { return _SmtpUserPassword; }
			set { _SmtpUserPassword = value; }
		}

		private static Encoding _DefaultEncoding = Encoding.UTF8;
		public static Encoding DefaultEncoding
		{
			get { return _DefaultEncoding; }
			set { _DefaultEncoding = value; }
		}
		#endregion Static properties

		#region Properties
		private string _SubjectTemplate;
		public string SubjectTemplate
		{
			get { return _SubjectTemplate; }
			set { _SubjectTemplate = value; }
		}

		private List<MailAddress> _To = new List<MailAddress>();
		public List<MailAddress> To
		{
			get { return _To; }
			set { _To = value; }
		}

		private NameValueCollection _Headers = new NameValueCollection();
		public NameValueCollection Headers
		{
			get { return _Headers; }
		}


		private List<MailAddress> _Bcc = new List<MailAddress>();
		public List<MailAddress> Bcc
		{
			get { return _Bcc; }
			set { _Bcc = value; }
		}

		private List<MailAddress> _Cc = new List<MailAddress>();
		public List<MailAddress> Cc
		{
			get { return _Cc; }
			set { _Cc = value; }
		}

		private MailAddress _Sender;
		public MailAddress Sender
		{
			get { return _Sender; }
			set { _Sender = value; }
		}

		private List<string> _AttachmentFile = new List<string>();
		public List<string> AttachmentFile
		{
			get { return _AttachmentFile; }
			set { _AttachmentFile = value; }
		}

		private string _BodyTemplate;
		public string BodyTemplate
		{
			get { return _BodyTemplate; }
			set { _BodyTemplate = value; }
		}

		private string _HtmlBodyTemplate;
		public string HtmlBodyTemplate
		{
			get { return _HtmlBodyTemplate; }
			set { _HtmlBodyTemplate = value; }
		}

		private List<object> _Parameters = new List<object>();
		public List<object> Parameters
		{
			get { return _Parameters; }
			set { _Parameters = value; }
		}

		private Dictionary<string, object> _ParametersDic = new Dictionary<string, object>();
		public Dictionary<string, object> ParametersDic
		{
			get { return _ParametersDic; }
			set { _ParametersDic = value; }
		}

		private List<Type> _SupportedTypes = new List<Type>();
		public List<Type> SupportedTypes
		{
			get { return _SupportedTypes; }
			set { _SupportedTypes = value; }
		}


		private Encoding _MessageEncoding = DefaultEncoding;
		public Encoding MessageEncoding
		{
			get { return _MessageEncoding; }
			set { _MessageEncoding = value; }
		}

		private MailAddress _ReplyTo;
		public MailAddress ReplyTo
		{
			get { return _ReplyTo; }
			set { _ReplyTo = value; }
		}

		private DeliveryNotificationOptions _DeliveryNotificationOptions;
		public DeliveryNotificationOptions DeliveryNotificationOptions
		{
			get
			{
				return this._DeliveryNotificationOptions;
			}
			set
			{
				if (((DeliveryNotificationOptions.Delay | DeliveryNotificationOptions.OnFailure | DeliveryNotificationOptions.OnSuccess) < value) && (value != DeliveryNotificationOptions.Never))
				{
					throw new ArgumentOutOfRangeException("value");
				}
				this._DeliveryNotificationOptions = value;
			}
		}

		#endregion Properties

		#region Constructors
		public MailHelper()
		{
		}
		public MailHelper(string templateName)
		{
			this.LoadTemplate(templateName);
		}
		#endregion Constructors

		#region Public methods
		public void LoadTemplate(string templateName)
		{
			XmlDocument xDoc = new XmlDocument();
			xDoc.Load(this.GetCultureDependedTemplate(templateName));

			// Subject
			this.SubjectTemplate = xDoc.SelectSingleNode("//Subject").InnerText;


			// Sender
			if (!string.IsNullOrEmpty(xDoc.SelectSingleNode("//Sender").Attributes["Email"].Value))
				Sender = new MailAddress(
					xDoc.SelectSingleNode("//Sender").Attributes["Email"].Value,
					xDoc.SelectSingleNode("//Sender").Attributes["Name"].Value,
					this.MessageEncoding);


			// TO
			XmlNodeList toNodes = xDoc.SelectNodes("//To");
			foreach (XmlNode toNode in toNodes)
			{
				string toEmail = toNode.Attributes["Email"].Value;
				string toName = toNode.Attributes["Name"].Value;

				this.To.Add(new MailAddress(toEmail, toName, this.MessageEncoding));
			}


			// BCC copies
			XmlNodeList bccNodes = xDoc.SelectNodes("//Bcc");
			foreach (XmlNode bccNode in bccNodes)
			{
				string email = bccNode.Attributes["Email"].Value;
				string name = bccNode.Attributes["Name"].Value;

				this.Bcc.Add(new MailAddress(email, name, this.MessageEncoding));
			}


			// Body
			if (xDoc.SelectSingleNode("//Body") != null)
				this.BodyTemplate = xDoc.SelectSingleNode("//Body").InnerText;


			// Html Body
			if (xDoc.SelectSingleNode("//HtmlBody") != null)
				this.HtmlBodyTemplate = xDoc.SelectSingleNode("//HtmlBody").InnerText;
		}

		public string GetBody()
		{
			return ParseTemplate(BodyTemplate);
		}
		public string GetHtmlBody()
		{
			return ParseTemplate(HtmlBodyTemplate);
		}
		public string GetSubject()
		{
			return ParseTemplate(SubjectTemplate);
		}

		public void SendMail()
		{
			MailMessage message = new MailMessage();
			message.BodyEncoding = Encoding.UTF8;


			// To addresses
			foreach (MailAddress to in To) message.To.Add(to);

			// Cc copies
			foreach (MailAddress cc in Cc) message.CC.Add(cc);

			// BBC copies
			foreach (MailAddress bcc in Bcc) message.Bcc.Add(bcc);


			// Sender
			if (Sender != null)
				message.Sender = Sender;
			else
				message.Sender = new MailAddress(MailHelper.SmtpUserName);
			message.From = message.Sender;


			// Subject
			message.Subject = this.GetSubject();
			message.SubjectEncoding = this.MessageEncoding;


			// Body
			message.BodyEncoding = this.MessageEncoding;
			string htmlBody = GetHtmlBody();
			if (!string.IsNullOrEmpty(htmlBody))
			{
				message.IsBodyHtml = true;
				message.Body = htmlBody;
			}
			else
			{
				message.IsBodyHtml = false;
				message.Body = GetBody();
			}


			// Add attachment files
			foreach (string atc in this.AttachmentFile)
				message.Attachments.Add(new Attachment(atc));


			// Sending message
			System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient();


			smtp.Host = SMTP;
			smtp.Port = Port;

			if (!string.IsNullOrEmpty(SmtpUserName) && !string.IsNullOrEmpty(SmtpUserPassword))
				smtp.Credentials = new NetworkCredential(SmtpUserName, SmtpUserPassword);


			if (this.ReplyTo != null) message.ReplyTo = this.ReplyTo;
			message.DeliveryNotificationOptions = this.DeliveryNotificationOptions;


			message.Headers.Add(this.Headers);

			smtp.Send(message);
			message.Dispose();
		}
		#endregion Public methods

		#region Private methods
		private string ParseTemplate(string template)
		{
			string result = template;
			
			foreach (object obj in Parameters)
			{
				result = TemplateHelper.FillTemplate(result, obj, SupportedTypes);
			}

			foreach (KeyValuePair<string, object> pair in this.ParametersDic)
			{
				result = TemplateHelper.FillTemplate(result, pair.Key, pair.Value);
			}

			return result;
		}
		private string GetCultureDependedTemplate(string templateFileName)
		{
			string ext = Path.GetExtension(templateFileName);
			string fileName = Path.GetFileNameWithoutExtension(templateFileName);
			string dir = Path.GetDirectoryName(templateFileName);

			string result = templateFileName;

			string FullCultureTemplate = Path.Combine(dir, fileName + "." + Thread.CurrentThread.CurrentUICulture.Name + ext);
			string MainCultureTemplate = Path.Combine(dir, fileName + "." + Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName + ext);

			if (File.Exists(FullCultureTemplate))
				result = FullCultureTemplate;
			else if (File.Exists(MainCultureTemplate))
				result = MainCultureTemplate;

			return result;
		}
		#endregion Private methods
	}
}

